<!-- 原题详情 -->
<template>
	<div
		:class="{
			'lsh-modal-box': true,
			resizing: !!resizingDrigger,
			...(resizingDrigger
				? {
						[resizingDrigger]: true
					}
				: {})
		}"
		ref="containerElement"
	>
		<transition name="zoom-modal" appear>
			<div
				class="lsh-modal-box__content"
				ref="el"
				v-show="visible"
				:style="boxStyle"
			>
				<div class="lsh-modal-title" ref="handle">
					<svg-icon class="lsh-drag-handle" name="drag-handle" />
					<slot name="title" />
					<svg-icon
						class="lsh-close-icon"
						name="close-fill"
						@click="visible = false"
					/>
				</div>
				<div class="lsh-modal-content">
					<slot name="content" />
					<div v-for="item in direction" :class="`lsh-resize-${item}`">
						<svg-icon
							class="lsh-resize-icon"
							name="resize-br"
							@mousedown="(e: MouseEvent) => hanClickTrigger(item, e)"
						/>
					</div>
				</div>
			</div>
		</transition>
	</div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useDraggable, useEventListener } from '@vueuse/core'
const visible = defineModel('visible')
//拖拽目标元素
const el = ref<HTMLElement | null>(null)
//用于计算边界限制的元素
const containerElement = ref<HTMLElement | null>(null)
//触发拖动事件的句柄。
const handle = ref<HTMLElement | null>(null)
const { x, y } = useDraggable(el, {
	initialValue: { x: 0, y: 0 },
	containerElement, //边界检测
	handle
})
const direction = ['bl', 'br']
const resizingDrigger = ref<string | undefined>(undefined)
let oldPos: { x: number; y: number } | undefined
let defaultCursor = ''
const cWidth = ref()
const cHeight = ref()
const hanClickTrigger = (dir: string, e: MouseEvent) => {
	resizingDrigger.value = dir
	oldPos = {
		x: e.x,
		y: e.y
	}
	defaultCursor = window.getComputedStyle(document.body).cursor
	document.body.style.cursor = ['bl'].includes(resizingDrigger.value)
		? 'sw-resize'
		: 'se-resize'
}

const getSize = (v: string): number => {
	if (v.includes('%')) return 0
	const sizeStr = v.split('px')[0]
	const size = parseFloat(sizeStr)
	return isNaN(size) ? 0 : size
}
const computedStyle = computed(() => {
	if (el.value) {
		const style = window.getComputedStyle(el.value)
		return {
			width: el.value.offsetWidth,
			height: el.value.offsetHeight,
			minWidth: getSize(style.minWidth),
			maxWidth: getSize(style.maxWidth),
			minHeight: getSize(style.minHeight),
			maxHeight: getSize(style.maxHeight)
		}
	}
	return {
		minWidth: 0,
		maxWidth: 0,
		minHeight: 0,
		maxHeight: 0
	}
})
const boxStyle = computed(() => {
	return {
		width: cWidth.value + 'px',
		height: cHeight.value + 'px',
		top: y.value + 'px',
		left: x.value + 'px'
	}
})
useEventListener('mousemove', (e) => {
	if (!resizingDrigger.value) return
	if (!oldPos) return

	// 获取调整前的尺寸
	const oldWidth = cWidth.value ?? computedStyle.value.width
	const oldHeight = cHeight.value ?? computedStyle.value.height

	// 计算新的尺寸
	const movementX = e.x - oldPos.x
	const movementY = e.y - oldPos.y

	// 计算宽度
	let calcWidth =
		oldWidth + (resizingDrigger.value.includes('r') ? movementX : -movementX)
	if (calcWidth < computedStyle.value.minWidth)
		calcWidth = computedStyle.value.minWidth
	if (
		computedStyle.value.maxWidth !== 0 &&
		calcWidth > computedStyle.value.maxWidth
	)
		calcWidth = computedStyle.value.maxWidth

	// 计算高度
	let calcHeight =
		oldHeight + (resizingDrigger.value.includes('b') ? movementY : -movementY)
	if (calcHeight < computedStyle.value.minHeight)
		calcHeight = computedStyle.value.minHeight
	if (
		computedStyle.value.maxHeight !== 0 &&
		calcHeight > computedStyle.value.maxHeight
	)
		calcHeight = computedStyle.value.maxHeight

	// 处理左下角缩放逻辑
	if (resizingDrigger.value === 'bl') {
		// 计算宽度变化量并调整 left 位置
		const deltaWidth = calcWidth - oldWidth
		x.value -= deltaWidth
	}

	// 更新尺寸
	cWidth.value = calcWidth
	cHeight.value = calcHeight
	oldPos = { x: e.x, y: e.y }
})
useEventListener('mouseup', () => {
	if (!resizingDrigger.value) return
	resizingDrigger.value = undefined
	document.body.style.cursor = defaultCursor
})
const init = () => {
	cHeight.value = 600
	cWidth.value = 304
	x.value = containerElement.value?.scrollWidth
		? containerElement.value?.scrollWidth - 304
		: 0
	y.value = 0
}
watch(
	() => visible.value,
	(v) => {
		if (!v) return
		init()
	}
)
</script>
<style scoped lang="less">
// used by modal
.zoom-modal-enter-from,
.zoom-modal-appear-from,
.zoom-modal-leave-to {
	transform: scale(0.5, 0.5);
	opacity: 0;
}
.zoom-modal-enter-to,
.zoom-modal-appear-to,
.zoom-modal-leave-from {
	transform: scale(1, 1);
	opacity: 1;
}
.zoom-modal-enter-active,
.zoom-modal-appear-active,
.zoom-modal-leave-active {
	transition:
		opacity 0.4s cubic-bezier(0.3, 1.3, 0.3, 1),
		transform 0.4s cubic-bezier(0.3, 1.3, 0.3, 1);
}
.lsh-modal-box {
	position: absolute;
	inset: 6px;
	overflow: hidden;
	pointer-events: none;
	&.resizing {
		pointer-events: all;
	}
	&.bl {
		cursor: sw-resize;
		.lsh-resize-bl .lsh-resize-icon {
			color: rgba(85, 124, 167, 1);
		}
	}
	&.br {
		cursor: se-resize;
		.lsh-resize-br .lsh-resize-icon {
			color: rgba(85, 124, 167, 1);
		}
	}
	.lsh-resize-icon {
		font-size: 28px;
		color: rgba(201, 206, 214, 1);
		&:hover {
			color: rgba(85, 124, 167, 1);
		}
	}
	.lsh-modal-box__content {
		min-width: 304px;
		max-width: 600px;
		min-height: 200px;
		max-height: 600px;
		width: 304px;
		border-radius: 16px;
		background: #fff;
		box-shadow: 0px 0px 20px 0px rgba(85, 124, 167, 0.12);
		position: absolute;
		right: 0;
		top: 0;
		pointer-events: auto;
		user-select: none;
		overflow: hidden;
    display: flex;
    flex-direction: column;
		.lsh-modal-title {
      flex-shrink: 0;
			cursor: move;
			display: flex;
			align-items: center;
			justify-content: space-between;
			padding: 16px;
			border-bottom: 1px solid #f2f5fa;
			position: relative;
			.lsh-close-icon {
				cursor: pointer;
			}
			.lsh-drag-handle {
				position: absolute;
				font-size: 14px;
				top: 0;
				left: 50%;
				transform: translateX(-50%);
				color: rgba(201, 206, 214, 1);
			}
		}
		.lsh-modal-content {
      flex: 1;
      overflow: hidden;
			.lsh-resize-bl {
				position: absolute;
				bottom: 0;
				left: 0;
				.lsh-resize-icon {
					cursor: sw-resize;
					transform: rotate(90deg);
					transform-origin: center;
				}
			}
			.lsh-resize-br {
				position: absolute;
				bottom: 0;
				right: 0;
				.lsh-resize-icon {
					cursor: se-resize;
				}
			}
		}
	}
}
</style>
